package com.vijay.extension.spring;

import com.vijay.extension.annotation.SpringExtension;
import com.vijay.extension.annotation.SpringKey;
import com.vijay.extension.common.Context;
import org.springframework.beans.factory.BeanFactory;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class SpringExtensionProxy<T> implements InvocationHandler {

    private Class<T> extensionInterface;

    private BeanFactory factory;

    public SpringExtensionProxy(Class<T> extensionInterface, BeanFactory factory) {

        this.extensionInterface = extensionInterface;
        this.factory = factory;
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        if (method.getDeclaringClass() == Object.class) {

            return method.invoke(this, args);

        }

        String[] candidates = new String[2];

        SpringExtension extAnnotation = extensionInterface.getAnnotation(SpringExtension.class);

        if (extAnnotation != null) {

            candidates[1] = extAnnotation.value();

        }

        SpringKey keyAnnotation = method.getAnnotation(SpringKey.class);
        if (keyAnnotation != null) {

            String key = keyAnnotation.value();

            if (key != null && !key.isEmpty()) {
                for (Object arg : args) {
                    if (Context.class.isAssignableFrom(arg.getClass())) {
                        candidates[0] = Context.class.cast(arg).getParameter(key, candidates[1]);
                        break;
                    }
                }
            }
        }

        //real invoke delegate by bean
        for (String candidate : candidates) {
            T bean = factory.getBean(candidate, extensionInterface);
            if (bean != null) {
                return method.invoke(bean, args);
            }
        }


        throw new UnsupportedOperationException("UnsupportedOperation @SpringExtension or @SpringKey,Please check");
    }
}
